home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / vidhrdw / liberatr.c < prev    next >
C/C++ Source or Header  |  2000-04-04  |  15KB  |  481 lines

  1. /***************************************************************************
  2.  
  3.   liberator.c - 'vidhrdw.c'
  4.  
  5.   Functions to emulate the video hardware of the machine.
  6.  
  7.    Liberator's screen is 256 pixels by 256 pixels.  The
  8.      round planet in the middle of the screen is 128 pixels
  9.      tall by 96 equivalent (192 at double pixel rate).  The
  10.      emulator needs to account for the aspect ratio of 4/3
  11.      from the arcade video system in order to make the planet
  12.      appear round.
  13.  
  14. ***************************************************************************/
  15.  
  16. #include "driver.h"
  17. #include "vidhrdw/generic.h"
  18.  
  19.  
  20. unsigned char *liberatr_bitmapram;
  21.  
  22.  
  23. void liberatr_vh_stop(void);
  24.  
  25.  
  26. /*
  27.     The following structure describes the (up to 32) line segments
  28.     that make up one horizontal line (latitude) for one display frame of the planet.
  29.     Note: this and the following structure is only used to collect the
  30.     data before it is packed for actual use.
  31. */
  32. typedef struct
  33. {
  34.     UINT8    segment_count;        /* the number of segments on this line */
  35.     UINT8    max_x;                /* the maximum value of x_array for this line */
  36.     UINT8    color_array[32];    /* the color values  */
  37.     UINT8    x_array[32];        /* and maximum x values for each segment  */
  38. } Liberator_Segs;
  39.  
  40. /*
  41.     The following structure describes the lines (latitudes)
  42.     that make up one complete display frame of the planet.
  43.     Note: this and the previous structure is only used to collect the
  44.     data before it is packed for actual use.
  45. */
  46. typedef struct
  47. {
  48.     Liberator_Segs line[ 0x80 ];
  49. } Liberator_Frame;
  50.  
  51.  
  52. /*
  53.     The following structure collects the 256 frames of the
  54.     planet (one per value of longitude).
  55.     The data is packed segment_count,segment_start,color,length,color,length,...  then
  56.                        segment_count,segment_start,color,length,color,length...  for the next line, etc
  57.     for the 128 lines.
  58. */
  59. typedef struct
  60. {
  61.     UINT8 *frame[256];
  62. } Liberator_Planet;
  63.  
  64.  
  65. /*
  66.     The following two arrays are Prom dumps off the processor
  67.     board.
  68. */
  69.  
  70. static UINT8 latitude_scale[] = {
  71.     0x25,0x3A,0x4A,0x55,0x5F,0x6A,0x75,0x7A,0x80,0x8A,0x8F,0x95,0x9A,0xA0,0xA5,0xAA,
  72.     0xB0,0xB5,0xB5,0xBA,0xC0,0xC0,0xC5,0xCA,0xCA,0xCF,0xCF,0xD5,0xD5,0xDA,0xDA,0xDF,
  73.     0xDF,0xE5,0xE5,0xE5,0xEA,0xEA,0xEA,0xEF,0xEF,0xEF,0xEF,0xF5,0xF5,0xF5,0xF5,0xFA,
  74.     0xFA,0xFA,0xFA,0xFA,0xFA,0xFA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  75.     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0xFA,0xFA,0xFA,0xFA,0xFA,
  76.     0xFA,0xF5,0xF5,0xF5,0xF5,0xEF,0xEF,0xEF,0xEF,0xEA,0xEA,0xEA,0xE5,0xE5,0xE5,0xDF,
  77.     0xDF,0xDA,0xDA,0xD5,0xD5,0xCF,0xCF,0xCA,0xCA,0xC5,0xC0,0xC0,0xBA,0xB5,0xB5,0xB0,
  78.     0xAA,0xA5,0xA0,0x9A,0x95,0x8F,0x8A,0x80,0x7A,0x75,0x6A,0x5F,0x55,0x4A,0x3A,0x25 };
  79.  
  80. static UINT8 longitude_scale[] = {
  81.     0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x03,
  82.     0x03,0x03,0x04,0x04,0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0A,
  83.     0x0A,0x0B,0x0B,0x0C,0x0C,0x0D,0x0E,0x0E,0x0F,0x10,0x10,0x11,0x12,0x12,0x13,0x14,
  84.     0x15,0x15,0x16,0x17,0x18,0x19,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x1F,0x20,0x21,
  85.     0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,
  86.     0x32,0x33,0x34,0x35,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x40,0x41,0x42,0x43,
  87.     0x44,0x45,0x46,0x48,0x49,0x4A,0x4B,0x4C,0x4E,0x4F,0x50,0x51,0x52,0x54,0x55,0x56,
  88.     0x57,0x58,0x5A,0x5B,0x5C,0x5D,0x5F,0x60,0x61,0x62,0x63,0x65,0x66,0x67,0x68,0x6A,
  89.     0x6B,0x6C,0x6D,0x6F,0x70,0x71,0x72,0x73,0x75,0x76,0x77,0x78,0x79,0x7B,0x7C,0x7D,
  90.     0x7E,0x7F,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
  91.     0x90,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,
  92.     0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAE,
  93.     0xAF,0xB0,0xB1,0xB2,0xB2,0xB3,0xB4,0xB5,0xB5,0xB6,0xB7,0xB7,0xB8,0xB9,0xB9,0xBA,
  94.     0xBB,0xBB,0xBC,0xBC,0xBD,0xBD,0xBE,0xBE,0xBF,0xBF,0xC0,0xC0,0xC1,0xC1,0xC2,0xC2,
  95.     0xC2,0xC3,0xC3,0xC4,0xC4,0xC4,0xC5,0xC5,0xC5,0xC5,0xC6,0xC6,0xC6,0xC6,0xC6,0xC7,
  96.     0xC7,0xC7,0xC7,0xC7,0xC7,0xC7,0xC7,0xC7,0xC7,0xC7,0xC7,0xFF,0xFF,0xFF,0xFF,0xFF };
  97.  
  98.  
  99. UINT8 *liberatr_base_ram;
  100. UINT8 *liberatr_planet_frame;
  101. UINT8 *liberatr_planet_select;
  102. UINT8 *liberatr_x;
  103. UINT8 *liberatr_y;
  104.  
  105. static UINT8 *liberatr_videoram;
  106.  
  107. /*
  108.     The following array collects the 2 different planet
  109.     descriptions, which are selected by liberatr_planetbit
  110. */
  111. static Liberator_Planet *liberatr_planet_segs[2];
  112.  
  113.  
  114. INLINE void bitmap_common_w(UINT8 x, UINT8 y, int data)
  115. {
  116.     int pen;
  117.  
  118.     liberatr_videoram[(y<<8) | x] = data & 0xe0;
  119.  
  120.     pen = Machine->pens[(data >> 5) + 0x10];
  121.     plot_pixel(Machine->scrbitmap, x, y, pen);
  122. }
  123.  
  124. WRITE_HANDLER( liberatr_bitmap_xy_w )
  125. {
  126.     bitmap_common_w(*liberatr_x, *liberatr_y, data);
  127. }
  128.  
  129. WRITE_HANDLER( liberatr_bitmap_w )
  130. {
  131.     UINT8 x = (offset & 0x3f) << 2;
  132.     UINT8 y = (offset >> 6);
  133.  
  134.     liberatr_bitmapram[offset] = data;
  135.  
  136.     bitmap_common_w(x , y, data);
  137.     bitmap_common_w(x+1, y, data);
  138.     bitmap_common_w(x+2, y, data);
  139.     bitmap_common_w(x+3, y, data);
  140. }
  141.  
  142.  
  143. READ_HANDLER( liberatr_bitmap_xy_r )
  144. {
  145.     return liberatr_videoram[((*liberatr_y)<<8) | (*liberatr_x)];
  146. }
  147.  
  148.  
  149. WRITE_HANDLER( liberatr_colorram_w )
  150. {
  151.     UINT8 r,g,b;
  152.  
  153.     /* handle the hardware flip of the bit order from 765 to 576 that
  154.        hardware does between vram and color ram */
  155.     static UINT8 penmap[] = {0x10,0x12,0x14,0x16,0x11,0x13,0x15,0x17};
  156.  
  157.  
  158.     /* scale it from 0x00-0xff */
  159.     r = ((~data >> 3) & 0x07) * 0x24 + 3;  if (r == 3)  r = 0;
  160.     g = ((~data     ) & 0x07) * 0x24 + 3;  if (g == 3)  g = 0;
  161.     b = ((~data >> 5) & 0x06) * 0x24 + 3;  if (b == 3)  b = 0;
  162.  
  163.     if (offset & 0x10)
  164.     {
  165.         /* bitmap colorram values */
  166.         offset = penmap[offset & 0x07];
  167.      }
  168.     else
  169.     {
  170.         offset ^= 0x0f;
  171.     }
  172.  
  173.     palette_change_color(offset,r,g,b);
  174. }
  175.  
  176.  
  177. /********************************************************************************************
  178.   liberatr_init_planet()
  179.  
  180.   The data for the planet is stored in ROM using a run-length type of encoding.  This
  181.   function does the conversion to the above structures and then a smaller
  182.   structure which is quicker to use in real time.
  183.  
  184.   Its a multi-step process, reflecting the history of the code.  Not quite as efficient
  185.   as it might be, but this is not realtime stuff, so who cares...
  186.  ********************************************************************************************/
  187. static int liberatr_init_planet(int planet_select)
  188. {
  189.     UINT16 longitude;
  190.     UINT8 *planet_rom;
  191.  
  192.  
  193.     planet_rom = memory_region(REGION_GFX1);
  194.  
  195.     /* for each starting longitude */
  196.     for (longitude = 0; longitude < 0x100; longitude++)
  197.     {
  198.         UINT8  i, latitude, start_segment, segment_count;
  199.         UINT16 total_segment_count;
  200.         UINT8  *buffer;
  201.         Liberator_Frame frame;
  202.         Liberator_Segs *line = 0;
  203.  
  204.  
  205.         total_segment_count = 0;
  206.  
  207.         /* for each latitude */
  208.         for (latitude = 0; latitude < 0x80; latitude++)
  209.         {
  210.             UINT8 segment, longitude_scale_factor, latitude_scale_factor, color, x=0;
  211.             UINT8 x_array[32], color_array[32], visible_array[32];
  212.  
  213.  
  214.             /* point to the structure which will hold the data for this line */
  215.             line = &frame.line[ latitude ];
  216.  
  217.             latitude_scale_factor = latitude_scale[ latitude ];
  218.  
  219.             /* for this latitude, load the 32 segments into the arrays */
  220.             for (segment = 0; segment < 0x20; segment++)
  221.             {
  222.                 UINT16 length, planet_data, address;
  223.  
  224.  
  225.                 /*
  226.                    read the planet picture ROM and get the
  227.                    latitude and longitude scaled from the scaling PROMS
  228.                 */
  229.                 address = (latitude << 5) + segment;
  230.                 if (planet_select)
  231.                     planet_data = (planet_rom[0x0000+address] << 8) + planet_rom[0x1000+address];
  232.                 else
  233.                     planet_data = (planet_rom[0x2000+address] << 8) + planet_rom[0x3000+address];
  234.  
  235.                 color  =  (planet_data >> 8) & 0x0f;
  236.                 length = ((planet_data << 1) & 0x1fe) + ((planet_data >> 15) & 0x01);
  237.  
  238.  
  239.                 /* scale the longitude limit (adding the starting longitude) */
  240.                 address = longitude + ( length >> 1 ) + ( length & 1 );        /* shift with rounding */
  241.                 visible_array[segment] = (( address & 0x100 ) ? 1 : 0);
  242.                 if (address & 0x80)
  243.                 {
  244.                     longitude_scale_factor = 0xff;
  245.                 }
  246.                 else
  247.                 {
  248.                     address = ((address & 0x7f) << 1) + (((length & 1) || visible_array[segment]) ? 0 : 1);
  249.                     longitude_scale_factor = longitude_scale[ address ];
  250.                 }
  251.  
  252.                 x_array[segment] = (((UINT16)latitude_scale_factor * (UINT16)longitude_scale_factor) + 0x80) >> 8;    /* round it */
  253.                 color_array[segment] = color;
  254.             }
  255.  
  256.             /*
  257.                determine which segment is the western horizon and
  258.                  leave 'segment' indexing it.
  259.             */
  260.             for (segment = 0; segment < 0x1f; segment++)    /* if not found, 'segment' = 0x1f */
  261.                 if (visible_array[segment]) break;
  262.  
  263.             /* transfer from the temporary arrays to the structure */
  264.             line->max_x = (latitude_scale_factor * 0xc0) >> 8;
  265.             if (line->max_x & 1)
  266.                 line->max_x += 1;                 /* make it even */
  267.  
  268.             /*
  269.                as part of the quest to reduce memory usage (and to a lesser degree
  270.                  execution time), stitch together segments that have the same color
  271.             */
  272.             segment_count = 0;
  273.             i = 0;
  274.             start_segment = segment;
  275.             do
  276.             {
  277.                 color = color_array[segment];
  278.                 while (color == color_array[segment])
  279.                 {
  280.                     x = x_array[segment];
  281.                     segment = (segment+1) & 0x1f;
  282.                     if (segment == start_segment)
  283.                         break;
  284.                 }
  285.                 line->color_array[ i ] = color;
  286.                 line->x_array[ i ]     = (x > line->max_x) ? line->max_x : x;
  287.                 i++;
  288.                 segment_count++;
  289.             } while ((i < 32) && (x <= line->max_x));
  290.  
  291.             total_segment_count += segment_count;
  292.             line->segment_count = segment_count;
  293.         }
  294.  
  295.         /* now that the all the lines have been processed, and we know how
  296.            many segments it will take to store the description, allocate the
  297.            space for it and copy the data to it.
  298.         */
  299.         if ((buffer = (UINT8 *)malloc(2*(128 + total_segment_count))) == 0)
  300.             return 1;
  301.  
  302.         liberatr_planet_segs[ planet_select ]->frame[ longitude ] = buffer;
  303.  
  304.         for (latitude = 0; latitude < 0x80; latitude++)
  305.         {
  306.             UINT8 last_x;
  307.  
  308.  
  309.             line = &frame.line[ latitude ];
  310.             segment_count = line->segment_count;
  311.             *buffer++ = segment_count;
  312.             last_x = 0;
  313.  
  314.             /* calculate the bitmap's x coordinate for the western horizon
  315.                center of bitmap - (the number of planet pixels) / 4 */
  316.             *buffer++ = Machine->drv->screen_width/2 - (line->max_x + 2) / 4;
  317.  
  318.             for (i = 0; i < segment_count; i++)
  319.             {
  320.                 UINT8 current_x = (line->x_array[ i ] + 1) / 2;
  321.                 *buffer++ = line->color_array[ i ];
  322.                 *buffer++ = current_x - last_x;
  323.                 last_x = current_x;
  324.             }
  325.         }
  326.     }
  327.  
  328.     return 0;
  329. }
  330.  
  331.  
  332. /***************************************************************************
  333.  
  334.   Start the video hardware emulation.
  335.  
  336. ***************************************************************************/
  337. int liberatr_vh_start(void)
  338. {
  339.     liberatr_videoram = 0;
  340.     liberatr_planet_segs[0] = 0;
  341.     liberatr_planet_segs[1] = 0;
  342.  
  343.  
  344.     if ((liberatr_videoram = malloc(Machine->drv->screen_width * Machine->drv->screen_height)) == 0)
  345.     {
  346.         liberatr_vh_stop();
  347.         return 1;
  348.     }
  349.  
  350.     /* allocate the planet descriptor structure */
  351.     if (((liberatr_planet_segs[0] = malloc(sizeof(Liberator_Planet))) == 0) ||
  352.         ((liberatr_planet_segs[1] = malloc(sizeof(Liberator_Planet))) == 0))
  353.     {
  354.         liberatr_vh_stop();
  355.         return 1;
  356.     }
  357.  
  358.     memset(liberatr_planet_segs[0], 0, sizeof(Liberator_Planet));
  359.     memset(liberatr_planet_segs[1], 0, sizeof(Liberator_Planet));
  360.  
  361.     /* for each planet in the planet ROMs */
  362.     if (liberatr_init_planet(0) ||
  363.         liberatr_init_planet(1))
  364.     {
  365.         liberatr_vh_stop();
  366.         return 1;
  367.     }
  368.  
  369.     return 0;
  370. }
  371.  
  372. /***************************************************************************
  373.  
  374.   Stop the video hardware emulation.
  375.  
  376. ***************************************************************************/
  377. void liberatr_vh_stop(void)
  378. {
  379.     int i;
  380.  
  381.     if (liberatr_videoram)
  382.     {
  383.         free(liberatr_videoram);
  384.         liberatr_videoram = 0;
  385.     }
  386.     if (liberatr_planet_segs[0])
  387.     {
  388.         for (i = 0; i < 256; i++)
  389.             if (liberatr_planet_segs[0]->frame[i])
  390.                 free(liberatr_planet_segs[0]->frame[i]);
  391.         free(liberatr_planet_segs[0]);
  392.         liberatr_planet_segs[0] = 0;
  393.     }
  394.     if (liberatr_planet_segs[1])
  395.     {
  396.         for (i = 0; i < 256; i++)
  397.             if (liberatr_planet_segs[1]->frame[i])
  398.                 free(liberatr_planet_segs[1]->frame[i]);
  399.         free(liberatr_planet_segs[1]);
  400.         liberatr_planet_segs[1] = 0;
  401.     }
  402. }
  403.  
  404.  
  405. /***************************************************************************
  406.  
  407.   Draw the game screen in the given osd_bitmap.
  408.   Do NOT call osd_update_display() from this function, it will be called by
  409.   the main emulation engine.
  410.  
  411. ***************************************************************************/
  412.  
  413. static void liberatr_draw_planet(void)
  414. {
  415.     UINT8 latitude;
  416.     UINT8 *buffer;
  417.  
  418.  
  419.     buffer = liberatr_planet_segs[ (*liberatr_planet_select >> 4) & 0x01 ]->frame[ *liberatr_planet_frame ];
  420.  
  421.     /* for each latitude */
  422.     for (latitude = 0; latitude < 0x80; latitude++)
  423.     {
  424.         UINT8 base_color, segment, segment_count, x, y;
  425.  
  426.         /* grab the color value for the base (if any) at this latitude */
  427.         base_color = liberatr_base_ram[latitude>>3] ^ 0x0f;
  428.  
  429.         segment_count = *buffer++;
  430.         x             = *buffer++;
  431.         y             = 64 + latitude;
  432.  
  433.         /* run through the segments, drawing its color until its x_array value comes up. */
  434.         for (segment = 0; segment < segment_count; segment++)
  435.         {
  436.             UINT8 color, segment_length, i;
  437.             UINT16 pen;
  438.  
  439.             color = *buffer++;
  440.             if ((color & 0x0c) == 0x0c)
  441.                 color = base_color;
  442.  
  443.             pen = Machine->pens[color];
  444.  
  445.             segment_length = *buffer++;
  446.  
  447.             for (i = 0; i < segment_length; i++, x++)
  448.             {
  449.                 /* only plot pixels that don't cover the foreground up */
  450.                 if (!liberatr_videoram[(y<<8) | x])
  451.                     plot_pixel(Machine->scrbitmap, x, y, pen);
  452.             }
  453.         }
  454.     }
  455. }
  456.  
  457.  
  458. void liberatr_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
  459. {
  460.     if (palette_recalc() || full_refresh)
  461.     {
  462.         UINT8 liberatr_y_save = *liberatr_y;
  463.         UINT8 liberatr_x_save = *liberatr_x;
  464.  
  465.         /* redraw bitmap */
  466.         for (*liberatr_y = Machine->drv->visible_area.min_y; *liberatr_y < Machine->drv->visible_area.max_y; (*liberatr_y)++)
  467.         {
  468.             for (*liberatr_x = Machine->drv->visible_area.min_x; *liberatr_x < Machine->drv->visible_area.max_x; (*liberatr_x)++)
  469.             {
  470.                 liberatr_bitmap_xy_w(0, liberatr_bitmap_xy_r(0));
  471.             }
  472.         }
  473.  
  474.         *liberatr_y = liberatr_y_save;
  475.         *liberatr_x = liberatr_x_save;
  476.     }
  477.  
  478.     /* draw the planet */
  479.     liberatr_draw_planet();
  480. }
  481.